package com.xiaotu.spider.douban.pageprocessor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.xiaotu.common.exception.SpiderException;
import com.xiaotu.common.exception.SpiderExceptionCode;
import com.xiaotu.common.model.TVDouBanModel;
import com.xiaotu.common.util.Constants;
import com.xiaotu.common.util.KeywordEncode;
import com.xiaotu.common.util.PageUtils;
import com.xiaotu.common.util.RegexUtils;
import com.xiaotu.common.util.TVProcessUtils;
import com.xiaotu.spider.APageProcessor;

import net.sf.json.JSONObject;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;

/**
 * 豆瓣爬取类
 */
@Component("DouBanReviesPageProcessor")
@Scope("prototype")
public class DouBanReviesPageProcessor extends APageProcessor
{
    @Override
    protected Request getStartRequest(JSONObject target)
    {
        return new Request("https://www.douban.com/search?cat=1002&q=" + KeywordEncode.encode(target.getString
                ("tvName")));
    }

    @Override
    public String getPageDataType(Page page)
    {
        String url = page.getUrl().toString();
        if (url.contains("https://www.douban.com/search?cat=1002&q="))
            return Constants.PageDataType.SEARCH_LIST;
        else if (url.contains("https://www.douban.com/link2"))
            return Constants.PageDataType.TV_RECORD;
        else if (url.contains("comments"))
            return Constants.PageDataType.TV_COMMENT;
        return Constants.PageDataType.SEARCH_LIST;
    }

    @Override
    public void process(Page page)
    {
        Map<String, Object> tvMap = page.getRequest().getExtras();
        switch (this.getPageDataType(page))
        {
            case Constants.PageDataType.SEARCH_LIST:
                this.searchListProcess(page, tvMap);
                break;
            case Constants.PageDataType.TV_RECORD:
                this.tvRecordProcess(page, tvMap);
                break;
            case Constants.PageDataType.TV_COMMENT:
                this.commentProcess(page, tvMap);
                break;
            default:
                break;
        }
    }

    @SuppressWarnings("unused")
    private void searchListProcess(Page page, Map<String, Object> tvMap)
    {
        List<String> links = page.getHtml().xpath("//div[@class='result-list']//div[@class='title']/h3/a/@href").all();
        List<String> names = page.getHtml().xpath("//div[@class='result-list']//div[@class='title']/h3/a/text()").all();
        names = names.stream().map(name -> name.trim()).collect(Collectors.toList());
        List<String> tvTypeList = page.getHtml().xpath
                ("//div[@class='result-list']//div[@class='title']/h3/span[1]/text()").all();

        List<String> infoStrList = page.getHtml().xpath
                ("//div[@class='result-list']//div[@class='title']//span[@class='subject-cast']/text()").all();
        List<List<String>> infoArrayList = new ArrayList<List<String>>();
        List<List<String>> directorList = new ArrayList<List<String>>();
        for (String infoStr : infoStrList)
            infoArrayList.add(Arrays.asList(infoStr.replace(" ", "").split("/")));

        if (links == null || links.size() == 0)
            throw new SpiderException(SpiderExceptionCode.DataInvalideException);
        if (links.size() != names.size() || links.size() != tvTypeList.size() || links.size() != infoArrayList.size())
            throw new SpiderException(SpiderExceptionCode.DataInvalideException);

        TVProcessUtils.addTVFromSearchList(page, tvMap, names, links, tvTypeList, infoArrayList, infoArrayList, new
                TVProcessUtils.TVMatcher()
                {
                    @Override
                    protected boolean addTV(Page page, Map<String, Object> tvinfoMap, String name, String tvType,
                            List<String> actorsList, List<String> directorsList, String link, int idx)
                    {
                        if (TVProcessUtils.tvMatched(tvinfoMap, name.trim(), TVProcessUtils.getTVType(tvType
                                .replaceAll("\\[|\\]", StringUtils.EMPTY)), actorsList, directorsList))
                        {
                            PageUtils.addTargetRequest(page, link, tvinfoMap, true);// 详情
                            return true;
                        }
                        return false;
                    }
                }, null);
    }

    private void tvRecordProcess(Page page, Map<String, Object> tvMap)
    {

        String score = page.getHtml()
                .xpath("//div[@class='rating_wrap clearbox']/p[1]/strong/text()|//div[@class='rating_wrap " +
                        "clearbox']/div[@class='rating_self clearfix']/strong/text()")
                .toString();
        String links = page.getHtml().xpath("//div[@id='comments-section']/div[@class='mod-hd']/h2/span/a/@href").toString();
        tvMap.put("score", score);
        PageUtils.addTargetRequest(page,links,tvMap);
    }

    private void commentProcess(Page page, Map<String, Object> tvMap)
    {
    	
        String reviewCount = page.getHtml()
                .xpath("//div[@class='article']/div[@class='clearfix Comments-hd']"
                		+ "/ul/li[@class='is-active']/span/text()").toString();
        reviewCount = RegexUtils.regexSearch(RegexUtils.REGEX_INTEGER, reviewCount);
        String reviewpraise = page.getHtml()
                .xpath("//div[@class='article']/div[@class='comment-filter']/label[2]"
                		+ "/span[@class='comment-percent']/text()").toString();
        String reviewgeneral = page.getHtml()
                .xpath("//div[@class='article']/div[@class='comment-filter']/label[3]"
                		+ "/span[@class='comment-percent']/text()").toString();
        String reviewbad = page.getHtml()
                .xpath("//div[@class='article']/div[@class='comment-filter']/label[4]"
                		+ "/span[@class='comment-percent']/text()").toString();
        
        page.putField(TVDouBanModel.class.getName(), new TVDouBanModel((String)tvMap.get("tvid"), 
        		(String)tvMap.get("tvName"), (String)tvMap.get("score"), reviewCount, 
        		reviewpraise, reviewgeneral, reviewbad));

    }

    @Override
    protected String getSpiderType()
    {
        return "DouBanRevies";
    }
}
